require 's3'

class S3Cache < ActionController::Caching::Fragments::UnthreadedFileStore
    def initialize(bucket, cache_directory)
      @aws_access_key = 'YOURAWSACCESSKEY'                    # your AWS ACCESS KEY
      @aws_secret_access_key = 'YOURAWSSECRETKEY'  # your SECRET
      @bucket = bucket
      @cache_path = cache_directory
      @conn = S3::AWSAuthConnection.new(@aws_access_key, @aws_secret_access_key)
      if ActionController::Base.allow_concurrency
        @mutex = Mutex.new
        FileStore.send(:include, ThreadSafety)
      end 
    end

    def write(name, value, options = nil) #:nodoc:
     s3 = @conn.put(@bucket, real_file_path(name), value,
                          {
                            "x-amz-acl" => "public-read",
                            "Content-Type" => "text/plain"
                          }
                        )
      unless s3.http_response.message == "OK"
        ActionController::Base.logger.error "Couldn't create cache directory: #{name} (#{s3.http_response.message})" if ActionController::Base.logger
      end
    end

    def read(name, options = nil) #:nodoc:
      s3 = @conn.get(@bucket, real_file_path(name))
      s3.http_response.message == "OK" ? s3.object.data : nil
    end

    def delete(name, options) #:nodoc:
      s3 = @conn.delete(@bucket, real_file_path(name))
      unless s3.http_response.message == "No Content"
        ActionController::Base.logger.error "Couldn't delete file: #{name} (#{s3.http_response.message})" if ActionController::Base.logger
      end
    end

    def delete_matched(matcher, options) #:nodoc:
     @conn.list_bucket(@bucket).entries.map { |entry| entry.key }.each do |f|
        if f =~ matcher
            delete(f, nil)
        end
      end
    end
end

#add ability to cache xml files
module ActionView
  module Helpers
   module CacheHelper 
     def cache_xml(name = {}, &block)
       @controller.cache_xml_fragment(block, name)
     end
   end
 end
end

module ActionController
  module Caching
    module Fragments
         # Called by CacheHelper#cache_xml
          def cache_xml_fragment(block, name = {}, options = nil)
            unless perform_caching then block.call; return end

            if cache = read_fragment(name, options)
              cache
            else
              write_fragment(name, block.call, options)
            end
          end
      # The below is needed to alter the file name structure. If it is an xml or rss file written with
      # cache_xml_fragment, this will write the file name as a regular xml
      # file name (/posts.xml) rather than posts.part=xml.cache.
      class UnthreadedFileStore

        private
          def real_file_path(name)
            if name["part=xml"]
              '%s/%s' % [@cache_path, name.gsub('?', '.').gsub(':', '.').gsub('part=xml', 'xml')]
            else
              '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')]
            end
          end
      end
    end
  end
end